// App.cpp

#include "StdAfx.h"

#include "../GUI/ExtractRes.h"

#include "Common/String/StringConvert.h"

#include "Common/System/Error.h"
#include "Common/FileSystem/FileFind.h"

#include "App.h"
#include "Common/String/FormatUtils.h"

#include "Common/System/Process.h"

#include "Common/Lang/LangUtils.h"
#include "Common/Registry/RegistryUtils.h"

using namespace Common;
using namespace System;


void CMainWnd::OnTab()
{
	m_wndPanel.SetFocusToList();
	RefreshTitle();
}

void CMainWnd::SetFocusToPath(int index)
{
	RefreshTitle();
	m_wndPanel._headerComboBox.SetFocus();
	m_wndPanel._headerComboBox.ShowDropDown();
}
void CMainWnd::SetListSettings()
{
	bool showDots = Registry::ReadShowDots();
	bool showRealFileIcons = Registry::ReadShowRealFileIcons();

	DWORD extendedStyle = LVS_EX_HEADERDRAGDROP;
	if (Registry::ReadFullRow())
	{
		extendedStyle |= LVS_EX_FULLROWSELECT;
	}
	if (Registry::ReadShowGrid())
	{
		extendedStyle |= LVS_EX_GRIDLINES;
	}
	bool mySelectionMode = Registry::ReadAlternativeSelection();

	if (Registry::ReadSingleClick())
	{
		extendedStyle |= LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT;
	}

	m_wndPanel._mySelectMode = mySelectionMode;
	m_wndPanel._showDots = showDots;
	m_wndPanel._showRealFileIcons = showRealFileIcons;
	m_wndPanel._exStyle = extendedStyle;


	if(m_wndPanel._listView.IsWindow())
	{
		DWORD style = (DWORD)m_wndPanel._listView.GetStyle();
		if (mySelectionMode)
		{
			style |= LVS_SINGLESEL;
		}
		else
		{
			style &= ~LVS_SINGLESEL;
		}
		m_wndPanel._listView.SetWindowLongPtr(GWL_STYLE, style);
	}
	m_wndPanel.SetExtendedStyle();
}

void CMainWnd::SetShowSystemMenu()
{
	ShowSystemMenu = Registry::ReadShowSystemMenu();
}

#ifndef ILC_COLOR32
#define ILC_COLOR32 0x0020
#endif

HRESULT CMainWnd::CreateOnePanel(const CString &mainPath, const CString &arcFormat,
								 bool &archiveIsOpened, bool &encrypted)
{
	CString path;
	if (mainPath.IsEmpty())
	{
		if (!::ReadPanelPath(path))
		{
			path.Empty();
		}
	}
	else
	{
		path = mainPath;
	}
	int id = 1000 + 100; //remove
	m_hWndClient = m_wndPanel.Create(_window, _window, m_hWndStatusBar,
									 id, path, arcFormat, this, &AppState, archiveIsOpened, encrypted);
	return S_OK;
}

static void CreateToolbar(HWND parent, CImageList &imageList,
						  CToolBarCtrl &toolBar,
						  bool largeButtons)
{
	toolBar.Attach(::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, 0
									| WS_CHILD
									| WS_VISIBLE
									| TBSTYLE_FLAT
									| TBSTYLE_TOOLTIPS
									| TBSTYLE_WRAPABLE
									// | TBSTYLE_AUTOSIZE
									// | CCS_NORESIZE
#ifdef UNDER_CE
									| CCS_NODIVIDER
									| CCS_NOPARENTALIGN
#endif
									, 0, 0, 0, 0, parent, NULL, _AtlBaseModule.GetModuleInstance(), NULL));

	// TB_BUTTONSTRUCTSIZE message, which is required for
	// backward compatibility.
	toolBar.SetButtonStructSize();

	imageList.Create(
		largeButtons ? 48 : 24,
		largeButtons ? 36 : 24,
		ILC_MASK | ILC_COLOR32, 0, 0);
	toolBar.SetImageList(imageList, 0);
}

struct CButtonInfo
{
	int CommandID;
	UINT StringResID;
	UINT32 LangID;
	CString GetText() const
	{
		return Lang::LangString(StringResID, LangID);
	}
};

static CButtonInfo g_StandardButtons[] =
{
	{ IDM_COPY_TO, IDS_BUTTON_COPY, 0x03020420},
	{ IDM_MOVE_TO, IDS_BUTTON_MOVE, 0x03020421},
	{ IDM_DELETE, IDS_BUTTON_DELETE, 0x03020422} ,
	{ IDM_FILE_PROPERTIES, IDS_BUTTON_INFO, 0x03020423}
};

static CButtonInfo g_ArchiveButtons[] =
{
	{ kAddCommand, IDS_ADD, 0x03020400},
	{ kExtractCommand, IDS_EXTRACT, 0x03020401},
	{ kTestCommand , IDS_TEST, 0x03020402}
};

static bool SetButtonText(int commandID, CButtonInfo* buttons, int numButtons, CString &s)
{
	for (int i = 0; i < numButtons; i++)
	{
		const CButtonInfo &b = buttons[i];
		if (b.CommandID == commandID)
		{
			s = b.GetText();
			return true;
		}
	}
	return false;
}

static void SetButtonText(int commandID, CString &s)
{
	if (SetButtonText(commandID, g_StandardButtons,
					  sizeof(g_StandardButtons) / sizeof(g_StandardButtons[0]), s))
	{
		return;
	}
	SetButtonText(commandID, g_ArchiveButtons,
				  sizeof(g_ArchiveButtons) / sizeof(g_ArchiveButtons[0]), s);
}

void CMainWnd::SaveToolbarChanges()
{
	SaveToolbar();
}


void CMainWnd::SetToolbarText()
{
	int i;
	TBBUTTONINFO tbInfo;
	tbInfo.cbSize = sizeof(TBBUTTONINFO);
	tbInfo.dwMask = TBIF_TEXT;
	for (i = 0; i < sizeof(g_ArchiveButtons) / sizeof(g_ArchiveButtons[0]); i++)
	{
		tbInfo.pszText =  (LPTSTR)(LPCTSTR)g_ArchiveButtons[i].GetText();
		m_CmdBar.SetButtonInfo(g_ArchiveButtons[i].CommandID, &tbInfo);
	}
	for (i = 0; i < sizeof(g_StandardButtons) / sizeof(g_StandardButtons[0]); i++)
	{
		tbInfo.pszText =  (LPTSTR)(LPCTSTR)g_StandardButtons[i].GetText();
		m_CmdBar.SetButtonInfo(g_StandardButtons[i].CommandID, &tbInfo);

	}
}

void CMainWnd::MarkZipContextAvailable(bool available /* = true*/, bool active /*= true*/)
{
	PROPVARIANT varNew;
	UI_CONTEXTAVAILABILITY isAvailable(UI_CONTEXTAVAILABILITY_NOTAVAILABLE);
	if (available)
	{
		if (active)
		{
			isAvailable = UI_CONTEXTAVAILABILITY_ACTIVE;
		}
		else
		{
			isAvailable = UI_CONTEXTAVAILABILITY_AVAILABLE;
		}
	}
	UIInitPropertyFromUInt32(UI_PKEY_ContextAvailable,
							 isAvailable, &varNew);
	SetProperty(IDM_ZIPMENU_TAB, UI_PKEY_ContextAvailable, varNew);
}

void MyLoadMenu();

HRESULT CMainWnd::CreateChildren(HWND hwnd, const CString &mainPath, const CString &arcFormat, int xSize, bool &archiveIsOpened, bool &encrypted)
{
	_window.Attach(hwnd);
#ifdef UNDER_CE
	_commandBar.Create(_AtlBaseModule.GetModuleInstance(), hwnd, 1);
#endif
#ifdef UNDER_CE
	_commandBar.AutoSize();
#endif


	// create command bar window
	HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault, NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE);

	// attach menu
	m_CmdBar.AttachMenu(GetMenu());
	// load command bar images
	if(LargeButtons)
	{
		m_CmdBar.LoadImages(IDR_MAINFRAME_HI);
	}
	else
	{
		m_CmdBar.LoadImages(IDR_MAINFRAME);
	}
	// remove old menu
	SetMenu(NULL);

	HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, IDR_MAINFRAME, FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE);

	CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);
	AddSimpleReBarBand(hWndCmdBar);
	AddSimpleReBarBand(hWndToolBar, NULL, TRUE);

	CreateSimpleStatusBar();



	SetToolbarText();


	AppState.Read();
	SetListSettings();

	CListMode listMode;
	ReadListMode(listMode);
	m_wndPanel._ListViewMode = listMode.Panel;
	m_wndPanel._xSize = xSize;
	m_wndPanel.m_directory.SetArcFlatMode(Registry::ReadFlatView());
	bool archiveIsOpened2 = false;
	bool encrypted2 = false;
	HRESULT hRes(CreateOnePanel(mainPath, arcFormat, archiveIsOpened2, encrypted2));
	if(S_OK != hRes)
	{
		return hRes;
	}
	archiveIsOpened = archiveIsOpened2;
	encrypted = encrypted2;

	m_wndPanel.SetFocusToList();
	UIAddToolBar(hWndToolBar);
	UISetCheck(ID_VIEW_TOOLBAR, 1);
	UISetCheck(ID_VIEW_STATUS_BAR, 1);

	MyLoadMenu();

	// register object for message filtering and idle updates
	CMessageLoop* pLoop = _Module.GetMessageLoop();
	ATLASSERT(pLoop != NULL);
	pLoop->AddMessageFilter(this);
	pLoop->AddIdleHandler(this);
	return S_OK;
}

void CMainWnd::Save()
{
	AppState.Save();
	CListMode listMode;
	CString path(m_wndPanel.m_directory.GetParentFolder());
	
	SavePanelPath(path);
	listMode.Panel = m_wndPanel.GetListViewMode();
	Registry::SaveFlatView(m_wndPanel.m_directory.GetArcFlatMode());
	SaveListMode(listMode);
}

void CMainWnd::ReleaseCom()
{
	// It's for unloading COM dll's: don't change it.
	m_wndPanel.Release();
}

static CString m_ToolTipBufferSys;

bool CMainWnd::OnNotify(UINT ctrlID, LPNMHDR pnmh, LRESULT & /* result */)
{
	if (pnmh->code == TTN_GETDISPINFO)
	{
		LPNMTTDISPINFO info = (LPNMTTDISPINFO)pnmh;
		info->hinst = 0;
		m_ToolTipBuffer.Empty();
		SetButtonText((int)info->hdr.idFrom, m_ToolTipBuffer);
		m_ToolTipBufferSys = String::GetSystemString(m_ToolTipBuffer);
		info->lpszText = (LPTSTR)(LPCTSTR)m_ToolTipBufferSys;
		return true;
	}
	return false;
}

void CMainWnd::RefreshTitle(bool always)
{
	CString path = GetFocusedPanel().m_directory.GetCurrentDirectory();
	if (path.IsEmpty())
	{
		path += Lang::LangString(IDS_APP_TITLE, 0x03000000);
	}
	if (!always && path == PrevTitle)
	{
		return;
	}
	PrevTitle = path;
	_window.SetWindowText(path);
}


static int Window_GetRealHeight(ATL::CWindow &w)
{
	RECT rect;
	w.GetWindowRect(&rect);
	int res = rect.bottom - rect.top;
#ifndef UNDER_CE
	WINDOWPLACEMENT placement;
	if (w.GetWindowPlacement(&placement))
	{
		res += placement.rcNormalPosition.top;
	}
#endif
	return res;
}
void CMainWnd::ExecuteCommand(UINT commandID)
{
	CPanel::CDisableTimerProcessing disableTimerProcessing1(m_wndPanel);

	switch (commandID)
	{
		case kAddCommand:
			AddToArchive();
			break;
		case kExtractCommand:
			ExtractArchives();
			break;
		case kTestCommand:
			TestArchives();
			break;
	}
}

LPCTSTR kWindowClass = _T("FM");


HWND CMainWnd::CreateThis(/*HINSTANCE hInstance, int nCmdShow*/)
{
	Lang::ReloadLangSmart();

	CString title = Lang::LangString(IDS_APP_TITLE, 0x03000000);

	DWORD style = WS_OVERLAPPEDWINDOW;

	RECT rect;
	bool maximized = false;
	bool windowPosIsRead = ReadWindowSize(rect, maximized);

	//TODO Disable for now
	//HWND hResult = baseFrame::CreateEx(NULL, rect, style);
	HWND hResult = baseFrame::CreateEx(NULL, NULL, style);
	if (!hResult)
	{
		return hResult;
	}

	SetWindowText(title);
	return hResult;
}

void CMainWnd::SaveWindowInfo()
{
#ifdef UNDER_CE
	RECT rect;
	if (!::GetWindowRect(aWnd, &rect))
	{
		return;
	}
	SaveWindowSize(rect, g_Maximized);
#else
	WINDOWPLACEMENT placement;
	placement.length = sizeof(placement);
	if (!::GetWindowPlacement(m_hWnd, &placement))
	{
		return;
	}
	SaveWindowSize(placement.rcNormalPosition, BOOLToBool(::IsZoomed(m_hWnd)));
#endif
}






LRESULT CMainWnd::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/)
{
	bool bRibbonUI = RunTimeHelper::IsRibbonUIAvailable();
	if (bRibbonUI)
	{
		UIAddMenu(GetMenu(), true);
	}
	else
	{
		CMenuHandle(GetMenu()).DeleteMenu(ID_VIEW_RIBBON, MF_BYCOMMAND);
	}

	RECT rect;
	GetClientRect(&rect);

	int xSize = rect.right;

	CreateDragTarget();
	bool archiveIsOpened;
	bool encrypted;
	bool needOpenFile = false;
	if (!GetMainPath().IsEmpty())
	{
		if (FileSystem::Find::DoesFileExist(GetMainPath()))
		{
			needOpenFile = true;
		}
	}
	HRESULT res = CreateChildren(m_hWnd, GetMainPath(), GetArcFormat(), xSize, archiveIsOpened, encrypted);

	if (res == E_ABORT)
	{
		return false;
	}

	if (needOpenFile && !archiveIsOpened || res != S_OK)
	{
		CString message = _T("Error");
		if (res == S_FALSE || res == S_OK)
		{
			if (encrypted)
			{
				message = String::PatternFormat(IDS_CANT_OPEN_ENCRYPTED_ARCHIVE, 0x0200060A, GetMainPath());
			}
			else
			{
				message = String::PatternFormat(IDS_CANT_OPEN_ARCHIVE, 0x02000609, GetMainPath());
			}
		}
		else
		{
			if (res != S_OK)
			{
				if (res == E_OUTOFMEMORY)
				{
					message = Lang::LangString(IDS_MEM_ERROR, 0x0200060B);
				}
				else if (!Error::FormatMessage(res, message))
				{
					message = _T("Error");
				}
			}
		}
		MessageBox(message, _T("7-zip"), MB_ICONERROR);
		return false;
	}

	// ::DragAcceptFiles(hWnd, TRUE);
	RegisterDragDrop(m_hWnd, _dropTarget);

	ShowRibbonUI(bRibbonUI);
	UISetText(IDM_VIEW_LIST_BTN, _T("List options"));
	UISetCheck(ID_VIEW_RIBBON, bRibbonUI);
	SetListViewMode(IDM_VIEW_DETAILS);
	MarkZipContextAvailable(false);
	return 0L;
}

HBITMAP CMainWnd::OnRibbonQueryImage(UINT nCmdID, REFPROPERTYKEY key)
{
	if (UI_PKEY_SmallImage == key)
	{
		switch (nCmdID)
		{
			case IDM_VIEW_LIST_BTN :
				if (NULL != m_hListViewToolbar)
				{
					return (HBITMAP)::CopyImage(m_hListViewToolbar, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
				}
				break;
			case IDM_VIEW_LIST_SORT :
				if (NULL != m_hListViewSort)
				{
					return (HBITMAP)::CopyImage(m_hListViewSort, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
				}
				break;
		}
	}
	return baseFrame::OnRibbonQueryImage(nCmdID, key);
}

LPCWSTR CMainWnd::OnRibbonQueryText(UINT nCmdID, REFPROPERTYKEY key)
{
	if (RibbonUI::k_(key) == RibbonUI::k_Label)
	{
		LPCTSTR sUI = CAutoUpdateUI::UIGetText(nCmdID);
		if (NULL != sUI)
		{
			LPCTSTR pos = wcschr(sUI, L'\t');

			if (sUI && IsRibbonUI() && IsRibbonID(nCmdID) && NULL != pos)
			{
				static WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 };
				int nPos = ((int)(pos - sUI));
				wcsncpy_s(sText, sUI, nPos);
				return sText;
			}
		}


	}
	return baseFrame::OnRibbonQueryText(nCmdID, key);

}

void CMainWnd::SortItemsWithPropID(PROPID propID)
{
	GetFocusedPanel().SortItemsWithPropID(IDM_VIEW_ARANGE_NO_SORT == propID ? 0 : propID);
	for (int i = IDM_VIEW_ARANGE_BY_NAME; i <= IDM_VIEW_ARANGE_NO_SORT; i++)
	{
		if (i == propID)
		{
			continue;
		}
		UISetCheck(i, false);
	}
	UISetCheck(propID, true);
	//Update ribbon if exists
	if(RunTimeHelper::IsRibbonUIAvailable())
	{
		if(HBITMAP hBmp = OnRibbonQueryImage(propID, UI_PKEY_SmallImage))
		{
			UISetText(IDM_VIEW_LIST_SORT, UIGetText(propID));
			m_hListViewSort = hBmp;
			InvalidateProperty(IDM_VIEW_LIST_SORT, UI_PKEY_SmallImage);
		}
	}
}

void CMainWnd::SetListViewMode(UINT32 index)
{
	UINT result = index - IDM_VIEW_LARGE_ICONS;
	if (result < 4)
	{
		GetFocusedPanel().SetListViewMode(result);
		for (int i = IDM_VIEW_LARGE_ICONS; i <= IDM_VIEW_DETAILS; i++)
		{
			if (i == index)
			{
				continue;
			}
			UISetCheck(i, false);
		}
		UISetCheck(index, true);
		//Update ribbon if exists
		if(RunTimeHelper::IsRibbonUIAvailable())
		{
			if(HBITMAP hBmp = OnRibbonQueryImage(index, UI_PKEY_SmallImage))
			{
				UISetText(IDM_VIEW_LIST_BTN, UIGetText(index));
				m_hListViewToolbar = hBmp;
				InvalidateProperty(IDM_VIEW_LIST_BTN, UI_PKEY_SmallImage);
			}
		}

		/*
		CMenu menu;
		menu.Attach(::GetSubMenu(::GetMenu(hWnd), kMenuIndex_View));
		menu.CheckRadioItem(IDM_VIEW_LARGE_ICONS, IDM_VIEW_DETAILS,
		    id, MF_BYCOMMAND);
		*/
	}

}

LRESULT CMainWnd::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL &bHandled)
{
	RevokeDragDrop(m_hWnd);
	_dropTarget.Release();

	Save();
	ReleaseCom();
	SaveWindowInfo();
	PostQuitMessage(0);
	return 0L;
}

BOOL CMainWnd::PreTranslateMessage(MSG* pMsg)
{
	return baseFrame::PreTranslateMessage(pMsg);
}

BOOL CMainWnd::OnIdle()
{
	UIUpdateToolBar();
	return FALSE;
}

LRESULT CMainWnd::OnViewToolBar(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL & /*bHandled*/)
{
	/*static BOOL bVisible = TRUE;  // initially visible
	bVisible = !bVisible;
	CReBarCtrl rebar = m_hWndToolBar;
	int nBandIndex = rebar.IdToIndex(ATL_IDW_BAND_FIRST + 1);   // toolbar is 2nd added band
	rebar.ShowBand(nBandIndex, bVisible);
	UISetCheck(ID_VIEW_TOOLBAR, bVisible);
	UpdateLayout(); */
	return 0;
}

LRESULT CMainWnd::OnViewStatusBar(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL & /*bHandled*/)
{
	/*BOOL bVisible = !::IsWindowVisible(m_hWndStatusBar);
	::ShowWindow(m_hWndStatusBar, bVisible ? SW_SHOWNOACTIVATE : SW_HIDE);
	UISetCheck(ID_VIEW_STATUS_BAR, bVisible);
	UpdateLayout(); */
	return 0;
}

LRESULT CMainWnd::OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL & /*bHandled*/)
{
	PostMessage(WM_CLOSE);
	return 0;
}



//Moved from DirectoryItemOpen.cpp
void CMainWnd::DiffFiles()
{
	const CPanel &panel = GetFocusedPanel();

	std::vector<UINT32> indices;
	panel.GetSelectedItemsIndices(indices);

	CString path1, path2;
	if (indices.size() == 2)
	{
		path1 = panel.m_directory.GetItemFullPath(indices[0]);
		path2 = panel.m_directory.GetItemFullPath(indices[1]);
	}
	else if (indices.size() == 1)
	{
		path1 = panel.m_directory.GetItemFullPath(indices[0]);
		const CString relPath = panel.m_directory.GetItemRelPath(indices[0]);
		std::vector<UINT32> indices2;
		m_wndPanel.GetSelectedItemsIndices(indices2);
		if (indices2.size() == 1)
		{
			path2 = m_wndPanel.m_directory.GetItemFullPath(indices2[0]);
		}
		else
		{
			path2 = m_wndPanel.m_directory.GetCurrentDirectory() + relPath;
		}
	}
	else
	{
		return;
	}

	CString command;
	Registry::ReadRegDiff(command);
	if (command.IsEmpty())
	{
		return;
	}

	CString param = FileManager::FileSystem::GetQuotedString(path1) + _T(' ') + FileManager::FileSystem::GetQuotedString(path2);

	DWORD res = Common::System::MyCreateProcess(command, param);
	if (0 == res)
	{
		return;
	}
	::MessageBox(_window, Lang::LangString(IDS_CANNOT_START_EDITOR, 0x03020282), _T("7-Zip"), MB_OK | MB_ICONSTOP);
}